package com.cpit.platform.security;


import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
import org.springframework.security.cas.authentication.CasAuthenticationProvider;
import org.springframework.security.cas.web.CasAuthenticationEntryPoint;
import org.springframework.security.cas.web.CasAuthenticationFilter;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;

import com.cpit.platform.config.CasProperties;
import com.cpit.platform.security.service.CustomUserDetailsServiceCas;

/**
 * 切换普通登陆模式和CAS登陆模式的方法：
 * 1：将本类的@注解去掉
 * 2：将WebMvcConfig类的registry.addViewController("/login").setViewName("login");注释掉
 * @author zhanghaibin
 */

/* @Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true) */
public class WebSecurityConfigCAS extends WebSecurityConfigurerAdapter {

	 @Autowired  
	 private CasProperties casProperties;
	 
	/**定义认证用户信息获取来源，密码校验规则等*/  
    @Override  
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {  
        super.configure(auth);  
        System.out.println("init cas provider");
        auth.authenticationProvider(casAuthenticationProvider());  
        //inMemoryAuthentication 从内存中获取  
        //auth.inMemoryAuthentication().withUser("chengli").password("123456").roles("USER")  
        //.and().withUser("admin").password("123456").roles("ADMIN");  
          
        //jdbcAuthentication从数据库中获取，但是默认是以security提供的表结构  
        //usersByUsernameQuery 指定查询用户SQL  
        //authoritiesByUsernameQuery 指定查询权限SQL  
        //auth.jdbcAuthentication().dataSource(dataSource).usersByUsernameQuery(query).authoritiesByUsernameQuery(query);  
          
        //注入userDetailsService，需要实现userDetailsService接口  
        //auth.userDetailsService(userDetailsService);  
    }  
    
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests()//配置安全策略  
		//.antMatchers("/","/hello").permitAll()//定义/请求不需要验证  
		.anyRequest().authenticated()//其余的所有请求都需要验证
		.antMatchers("/**/getCurrentUser").permitAll()
		.and()  
		.logout()  
		.permitAll()//定义logout不需要验证  
		.and().headers().frameOptions().disable().and()
		.formLogin();//使用form表单登录  

		http.exceptionHandling().authenticationEntryPoint(casAuthenticationEntryPoint())  
		.and()  
		.addFilter(casAuthenticationFilter())  
		.addFilterBefore(casLogoutFilter(), LogoutFilter.class)  
		.addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class);  
		http.csrf().disable(); //禁用CSRF  
	}
	
	 /**认证的入口*/  
    @Bean  
    public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {  
        CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();  
        casAuthenticationEntryPoint.setLoginUrl(casProperties.getCasServerLoginUrl());  
        casAuthenticationEntryPoint.setServiceProperties(serviceProperties());  
        return casAuthenticationEntryPoint;  
    }  
      
    /**指定service相关信息*/  
    @Bean  
    public ServiceProperties serviceProperties() {  
        ServiceProperties serviceProperties = new ServiceProperties();
        System.out.println("set service : " + casProperties.getAppServerUrl() + casProperties.getAppLoginUrl());
        serviceProperties.setService(casProperties.getAppServerUrl() + casProperties.getAppLoginUrl());  
        serviceProperties.setAuthenticateAllArtifacts(true);  
        return serviceProperties;  
    }  
      
    /**CAS认证过滤器*/  
    @Bean  
    public CasAuthenticationFilter casAuthenticationFilter() throws Exception {  
        CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();  
        casAuthenticationFilter.setAuthenticationManager(authenticationManager());  
        casAuthenticationFilter.setFilterProcessesUrl(casProperties.getAppLoginUrl());  
        return casAuthenticationFilter;  
    }  
      
    /**cas 认证 Provider*/  
    @Bean  
    public CasAuthenticationProvider casAuthenticationProvider() {  
        CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();  
        casAuthenticationProvider.setAuthenticationUserDetailsService(customUserDetailsService());  
        //casAuthenticationProvider.setUserDetailsService(customUserDetailsService()); //这里只是接口类型，实现的接口不一样，都可以的。  
        casAuthenticationProvider.setServiceProperties(serviceProperties());  
        casAuthenticationProvider.setTicketValidator(cas20ServiceTicketValidator());  
        casAuthenticationProvider.setKey("casAuthenticationProviderKey");  
        return casAuthenticationProvider;  
    }  
      
    /*@Bean 
    public UserDetailsService customUserDetailsService(){ 
        return new CustomUserDetailsService(); 
    }*/  
      
    /**用户自定义的AuthenticationUserDetailsService*/  
    @Bean  
    public AuthenticationUserDetailsService<CasAssertionAuthenticationToken> customUserDetailsService(){  
        return new CustomUserDetailsServiceCas();  
    }  
      
    @Bean  
    public Cas20ServiceTicketValidator cas20ServiceTicketValidator() {  
        return new Cas20ServiceTicketValidator(casProperties.getCasServerUrl());  
    }  
      
    /**单点登出过滤器*/  
    @Bean  
    public SingleSignOutFilter singleSignOutFilter() {  
        SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();  
        singleSignOutFilter.setCasServerUrlPrefix(casProperties.getCasServerUrl());  
        singleSignOutFilter.setIgnoreInitConfiguration(true);  
        return singleSignOutFilter;  
    }  
      
    /**请求单点退出过滤器*/  
    @Bean  
    public LogoutFilter casLogoutFilter() {  
        LogoutFilter logoutFilter = new LogoutFilter(casProperties.getCasServerLogoutUrl(), new SecurityContextLogoutHandler());  
        logoutFilter.setFilterProcessesUrl(casProperties.getAppLogoutUrl());  
        return logoutFilter;  
    }  

	@Override
	public void configure(WebSecurity web) throws Exception {
		web.ignoring().antMatchers("/assets/**","/css/**",
				"/images/**","/js/**","/jquery/**","/**/app/**");
	}

}
